/********************************************************/
/*	Copyright (C) 2016 Gong Li Bin		 	*/
/*	Project:	GoLib-1.0.0			*/
/*	Author:		gong_libin			*/
/*	Date:		2016_01_01			*/
/*	File:		GoSet.go			*/
/********************************************************/

package GoCap

import (
	"sort"
	"reflect"
)

/* uniq */
func GoSetUniq(v []interface{}) {
	for i, j := 0, 1; j < len(v); j ++ {
		if v[i] == v[j] {
			v[j] = nil
		} else {
			i = j
		}
	}
}

func __SetUniq(v interface{}) interface{} {
	r := __SetSlice(v)
	GoSetUniq(r)
	return r[:]
}

/* order */
func GoSetOrder(v []interface{}) {
	i, j, l := 0, 0, len(v)
	for ; i < l; {
		for ; j < l; {
			if nil != v[j] {
				j += 1
				i = j
			} else {
				break;
			}
		}
		for ; i < l; {
			if nil == v[i] {
				i += 1
			} else {
				break
			}
		}
		if i < l {
			v[j] = v[i]
			v[i] = nil
		}
	}
}

func __SetOrder(v interface{}) interface{} {
	r := __SetSlice(v)
	GoSetOrder(r)
	return r[:]
}

/* slice */
func __SetSlice(v interface{}) []interface{} {
	var ret []interface{}
	ref := reflect.ValueOf(v)
	if reflect.Slice == ref.Kind() {
		l := ref.Len()
		ret = make([]interface{}, l)
		for i := 0; i < l; i++ {
			ret[i] = ref.Index(i).Interface()
		}
	}
	return ret
}

/* func */
type GoSet interface {
	GoSetSort()
	GoSetFind()
	GoSetUniq()
	GoSetOrder()
}

/* basic */
type GoInt	[]int
type GoStr	[]string
type GoFlt	[]float64

func (i *GoInt) GoSetSort() {
	sort.Sort(sort.IntSlice(*i))
}

func (s *GoStr) GoSetSort() {
	sort.Sort(sort.StringSlice(*s))
}

func (f *GoFlt) GoSetSort() {
	sort.Sort(sort.Float64Slice(*f))
}

func (i *GoInt) GoSetFind(k int) int {
	return sort.SearchInts(*i, k)
}

func (s *GoStr) GoSetFind(k string) int {
	return sort.SearchStrings(*s, k)
}

func (f *GoFlt) GoSetFind(k float64) int {
	return sort.SearchFloat64s(*f, k)
}

func (i *GoInt) GoSetUniq() interface{} {
	return __SetUniq(*i)
}

func (s *GoStr) GoSetUniq() interface{} {
	return __SetUniq(*s)
}

func (f *GoFlt) GoSetUniq() interface{} {
	return __SetUniq(*f)
}

func (i *GoInt) GoSetOrder() interface{} {
	return __SetOrder(*i)
}

func (s *GoStr) GoSetOrder() interface{} {
	return __SetOrder(*s)
}

func (f *GoFlt) GoSetOrder() interface{} {
	return __SetOrder(*f)
}

/* GoObj */
type GoObj	[]struct {
	Key	interface{}
	Val	interface{}
}

func (o GoObj) Len() int {
	return len(o)
}

func (o GoObj) Swap(i, j int) {
	o[i], o[j] = o[j], o[i]
}

func (o GoObj) Less(i, j int) bool {
	var b bool = true
	switch o[i].Key.(type) {
		case int:
			b = o[i].Key.(int) < o[j].Key.(int)
		case uint:
			b = o[i].Key.(uint) < o[j].Key.(uint)
		case int16:
			b = o[i].Key.(int16) < o[j].Key.(int16)
		case int32:
			b = o[i].Key.(int32) < o[j].Key.(int32)
		case int64:
			b = o[i].Key.(int64) < o[j].Key.(int64)
		case uint16:
			b = o[i].Key.(uint16) < o[j].Key.(uint16)
		case uint32:
			b = o[i].Key.(uint32) < o[j].Key.(uint32)
		case uint64:
			b = o[i].Key.(uint64) < o[j].Key.(uint64)
		case string:
			b = o[i].Key.(string) < o[j].Key.(string)
		default:
	}

	return b
}

func (o GoObj) GoSetSort() {
	sort.Sort(o)
}

func (o GoObj) GoSetUniq() {
	for i, j := 0, 1; j < len(o); j ++ {
		if o[i].Key == o[j].Key {
			o[j].Val = nil
			o[j].Key = nil
		} else {
			i = j
		}
	}
}

func (o GoObj) GoSetOrder() {
	i, j, l := 0, 0, len(o)
	for ; i < l; {
		for ; j < l; {
			if nil != o[j].Key {
				j += 1
				i = j
			} else {
				break;
			}
		}
		for ; i < l; {
			if nil == o[i].Key {
				i += 1
			} else {
				break
			}
		}
		if i < l {
			o[j] = o[i]
			o[i].Key = nil
			o[i].Val = nil
		}
	}
}

func (o GoObj) GoSetFind(k interface{}) int {
	idx := 0
	switch k.(type) {
		case int:
			idx = sort.Search(o.Len(), func(i int) bool {return o[i].Key.(int) >= k.(int)})
		case uint:
			idx = sort.Search(o.Len(), func(i int) bool {return o[i].Key.(uint) >= k.(uint)})
		case int16:
			idx = sort.Search(o.Len(), func(i int) bool {return o[i].Key.(int16) >= k.(int16)})
		case int32:
			idx = sort.Search(o.Len(), func(i int) bool {return o[i].Key.(int32) >= k.(int32)})
		case int64:
			idx = sort.Search(o.Len(), func(i int) bool {return o[i].Key.(int64) >= k.(int64)})
		case uint16:
			idx = sort.Search(o.Len(), func(i int) bool {return o[i].Key.(uint16) >= k.(uint16)})
		case uint32:
			idx = sort.Search(o.Len(), func(i int) bool {return o[i].Key.(uint32) >= k.(uint32)})
		case uint64:
			idx = sort.Search(o.Len(), func(i int) bool {return o[i].Key.(uint64) >= k.(uint64)})
		case string:
			idx = sort.Search(o.Len(), func(i int) bool {return o[i].Key.(string) >= k.(string)})
		default:
	}
	return idx
}
